package br.com.ordersys.web.mail;

import java.util.Iterator;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.event.ConnectionEvent;
import javax.mail.event.ConnectionListener;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

public class MailSender {

	public static Session buildSession(String host, int port, final String userName, final String password, TransportType type) {
		Properties props = new Properties();

		if (type == TransportType.TLS) {
			props.put("mail.smtp.starttls.enable", "true");
		} else {
			props.put("mail.smtp.socketFactory.port", String.valueOf(port));
			props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		}

		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.host", host);
		props.put("mail.smtp.port", String.valueOf(port));

		return Session.getInstance(props, new javax.mail.Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(userName, password);
			}
		});
	}

	public static SendResult send(MailMessage msg, Session session) {
		final SendResult r = new SendResult();
		Transport t = null;
		
		try {
			Multipart mp = new MimeMultipart();

			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress(msg.getFrom()));

			setRecipients(msg, message);

			message.setSubject(msg.getSubject());

			BodyPart body = new MimeBodyPart();

			body.setContent(msg.getMessageText(), msg.getMimeType());
			mp.addBodyPart(body);

			addAttachments(mp, msg);

			message.setContent(mp);
			
			if(msg.getReplyTo() != null){
				message.setReplyTo(InternetAddress.parse(msg.getReplyTo()));
				message.addHeader("In-Reply-To", msg.getReplyTo());
			}

			t = session.getTransport("smtp");
			
			t.addConnectionListener(new ConnectionListener() {
				@Override
				public void opened(ConnectionEvent e) {
					r.connectionSucessful = true;
				}
				
				@Override
				public void disconnected(ConnectionEvent e) {}
				
				@Override
				public void closed(ConnectionEvent e) {}
			});
			
			t.connect();
			t.sendMessage(message,message.getAllRecipients());
			
			r.status = SendResult.Status.SUCESS;
		} catch (Exception e) {
			e.printStackTrace();
			r.status = SendResult.Status.FAIL;
			r.errorMessage = e.getMessage();
		} finally{
			try{
				if(t != null){
					t.close();
				}
			}catch(Exception ignored){}
		}

		return r;
	}

	private static void addAttachments(Multipart mp, MailMessage msg) throws Exception {
		for (MailMessage.Attachment attach : msg.getAttachments()) {
			MimeBodyPart part = new MimeBodyPart();
			ByteArrayDataSource ds = new ByteArrayDataSource(attach.getData(), attach.getMimeType());
			ds.setName(attach.getFileName());
			part.setFileName(attach.getFileName());

			part.setDataHandler(new DataHandler(ds));

			mp.addBodyPart(part);
		}
	}

	private static void setRecipients(MailMessage msg, Message m) throws Exception {
		if (msg.getRecipientsTo().isEmpty()) {
			throw new IllegalStateException("No recipients");
		}

		Iterator<String> ite = msg.getRecipientsTo().iterator();

		StringBuilder b = new StringBuilder();
		while (ite.hasNext()) {
			b.append(ite.next());
			if (ite.hasNext()) {
				b.append(",");
			}
		}

		m.setRecipients(Message.RecipientType.TO, InternetAddress.parse(b.toString()));
	}

	public static enum TransportType {
		TLS, SSL
	}

	public static class SendResult {
		Status status = Status.SUCESS;
		String errorMessage;
		boolean connectionSucessful;

		public static enum Status {
			SUCESS, FAIL
		}

		public Status getStatus() {
			return status;
		}

		public String getErrorMessage() {
			return errorMessage;
		}

		public boolean isConnectionSucessful() {
			return connectionSucessful;
		}
	}
}
